home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / vmmngr.zip / VMM.IN3 < prev    next >
Text File  |  1990-07-16  |  12KB  |  391 lines

  1. {*********************************************************}
  2. {*                   VMM.IN3 1.00                        *}
  3. {*********************************************************}
  4.  
  5.   procedure ErrorExit(Code : Word);
  6.     {-Make some housekeeping before halting program}
  7.   var
  8.     i : Byte;
  9.     P : VMMPtr;
  10.   begin
  11.     {if critical error, program will free all allocated Ems handles before exit}
  12.     for i := 0 to Pred(VmmInstances.GetValidElems) do begin
  13.       VmmInstances.GetElem(i, P);
  14.       P^.Done;
  15.     end;
  16.     RunError(Code);
  17.   end;
  18.  
  19.   {---------------------------------------------------------------------}
  20.  
  21.   {+++ VMM public methods +++}
  22.  
  23.   constructor VMM.Init(SwapFName : PathStr);
  24.     {-Create a new virtual memory manager with default options}
  25.   var
  26.     DefEmsToKeep : Word;
  27.     PagesAVail   : Word;
  28.   begin
  29.     {Evaluate how much EMS memory is available - Keep 10% free}
  30.     if VmmEmsInstalled then begin
  31.       PagesAvail := EmsPagesAvail;
  32.       if PagesAvail <> EmsErrorCode then
  33.         DefEmsToKeep := PagesAvail div 10;     {10% not used by VMM}
  34.     end
  35.     else
  36.       DefEmsToKeep := NoEms; {Prevent VMM from using Ems}
  37.  
  38.     if not VMM.InitCustom(MaxHeapAlloc,          {65521 bytes}
  39.                           DefIncr,               {128 bytes}
  40.                           DefFreeEntries div 2,  {1024 entries = 4096 bytes}
  41.                           DefFreeEntries,        {2048 entries = 8192 bytes}
  42.                           DefQueueEntries,       {512-1 entries}
  43.                           DefEmsToKeep,          {10% of Ems pages avail.}
  44.                           DefDskToKeep,          {1meg}
  45.                           SwapFName) then
  46.       Fail;
  47.   end;
  48.  
  49.   constructor VMM.InitCustom(RamSize : LongInt;
  50.                              Incr, MaxVmmEntries,
  51.                              MaxFreeEntries, VmmQueueEntries,
  52.                              EmsPagesToKeep : Word;
  53.                              DskToKeep : LongInt;
  54.                              SwapFName : PathStr);
  55.     {-Create a new virtual memory manager with custom options}
  56.   var
  57.     Err : Word;
  58.     P   : Pointer;
  59.   begin
  60.     if (not Root.init) then
  61.       Fail;
  62.  
  63.     {Initialize VMM data objects}
  64.     if   (not vmRamFreeList.Init(MaxFreeEntries, Incr))
  65.       or (VmmEmsInstalled
  66.           and (not vmEmsFreeList.Init(MaxFreeEntries, Incr)))
  67.           {if Ems not present doesn't initialize EmsFreeList}
  68.       or (not vmDskFreeList.Init(MaxFreeEntries, Incr))
  69.       or (not vmDescTable.Init(MaxVmmEntries, SizeOf(VmmDescriptor), Incr)
  70.       or (not vmLruQueue.Init(VmmQueueEntries*SizeOf(VmmHandle),
  71.                               SizeOf(VmmHandle), true)))
  72.       then begin
  73.         Done;
  74.         Fail;
  75.         {InitStatus has been loaded by FreeList or Queue constructor}
  76.       end;
  77.  
  78.     {Initialize Ram area - may be greater than 64k if the user-defined}
  79.     { UserGetMem function provides this capability}
  80.     if not UserGetMem(vmRamArea, RamSize) then begin
  81.       Done;
  82.       InitStatus := epFatal+ecOutOfMemory;
  83.       Fail;
  84.     end
  85.     else begin
  86.       vmRamAreaSize := RamSize;
  87.       {Create a free entry for the whole Ram area}
  88.       { so there is no need for a heap pointer}
  89.       with vmRamFreeList do
  90.         if AddFreeEntry(vmRamArea, vmRamAreaSize) <> vmRamAreaSize then begin
  91.           Done;
  92.           InitStatus := epFatal+ecOutOfRamEntries;
  93.           Fail;
  94.         end;
  95.     end;
  96.  
  97.     {Initialize options}
  98.     vmOptions := DefVmmOptions;
  99.     vmStatus := 0;
  100.  
  101.     {Process disk related information}
  102.     vmSwapFName := SwapFname;
  103.     if vmSwapFName = '' then
  104.       vmOptionsOff(vmUseDsk)
  105.     else begin
  106.       vmDskToKeep := DskToKeep;
  107.       vmEofPtr := 0;
  108.       {Open swap file}
  109.       vmSwapFName := FExpand(vmSwapFName);
  110.       Assign(vmF, vmSwapFName);
  111.       Rewrite(vmF, 1);          {This way we can write blocks of any size}
  112.       Err := IoResult;
  113.       if Err <> 0 then begin
  114.         Done;
  115.         InitStatus := epFatal+Err;
  116.         Fail;
  117.       end;
  118.     end;
  119.  
  120.     {Process Ems related information}
  121.     vmEmsToKeep := EmsPagesToKeep;
  122.     if (not VmmEmsInstalled)
  123.     or (vmEmsToKeep = NoEms) then
  124.       if vmOptionsAreOn(vmUseDsk) then
  125.         vmOptionsOff(vmUseEms)
  126.       else begin
  127.         {No resources for virtual memory}
  128.         Done;
  129.         InitStatus := epFatal+ecNoResources;
  130.         Fail;
  131.       end
  132.     else begin
  133.       P := EmsPageFramePtr;
  134.       vmEmsBaseSeg := VmmPtrRec(P).Seg;
  135.       {Offset part of returned pointer is always 0}
  136.     end;
  137.  
  138.     {Increment VmmInstances number of elements by one and store pointer}
  139.     P := @Self;
  140.     with VmmInstances do
  141.       SetElem(GetValidElems, P);
  142.     {Prevent deadlocks by keeping at least 3*vmRamAreaSize bytes}
  143.     { free on both virtual media}
  144.     Inc(VmmRamAreaSizeGlb, vmRamAreaSize*3);
  145.   end;
  146.  
  147.   destructor VMM.Done;
  148.     {-Destroy a virtual memory manager}
  149.   var
  150.     Err : Word;
  151.   begin
  152.     vmRamFreeList.Done;
  153.     if VmmEmsInstalled then
  154.       vmEmsFreeList.Done;
  155.     vmDskFreeList.Done;
  156.     vmDescTable.Done;
  157.     UserFreeMem(vmRamArea, vmRamAreaSize);
  158.     if vmOptionsAreOn(vmUseDsk) then
  159.       Close(vmF);
  160.     if vmOptionsAreOn(vmDeleteSwap) then
  161.       Erase(vmF);
  162.     Err := IoResult;
  163.     Dec(VmmRamAreaSizeGlb, vmRamAreaSize*3);
  164.     Root.Done;
  165.   end;
  166.  
  167.   function VMM.PeekStatus : Word;
  168.     {-Return VMM status}
  169.   begin
  170.     PeekStatus := vmStatus;
  171.   end;
  172.  
  173.   function VMM.GetStatus : Word;
  174.     {-Return and reset VMM status}
  175.   begin
  176.     GetStatus := vmStatus;
  177.     vmStatus := 0;
  178.   end;
  179.  
  180.   procedure VMM.Error(Code : Word);
  181.     {-Assign error code}
  182.   begin
  183.     vmStatus := Code;
  184.   end;
  185.  
  186.   procedure VMM.LinkToDerefHandler;
  187.     {-Instruct the dereference interrupt handler to refer to THIS manager}
  188.   begin
  189.     VmmActiveMgr := @Self;
  190.   end;
  191.  
  192.   function VMM.Lock(var Pt; Lockit : Boolean) : Boolean;
  193.     {-Lock or Unlock a VMM block in Ram}
  194.   var
  195.     H : Word;
  196.     P : Pointer absolute Pt;
  197.     D : VmmDescriptor;
  198.   begin
  199.     Lock := false;
  200.     if P = nil then
  201.       Exit;
  202.     H := VmmPtrRec(P).Seg;
  203.     {Get descriptor in descriptor table}
  204.     vmDescTable.GetElem(H, D);
  205.     if vmDescTable.GetStatus <> 0 then
  206.       exit;
  207.  
  208.     if Lockit then begin
  209.       SetByteFlag(D.Location, vmLocked);       {lock it}
  210.       vmLruQueue.Remove(H); {Cannot be paged out any more}
  211.     end
  212.     else begin
  213.       ClearByteFlag(D.Location, vmLocked);     {unlock it}
  214.       vmLruQueue.Remove(H);
  215.       vmLruQueue.PushTail(H); {Now can be paged out again}
  216.     end;
  217.     {Update descriptor table entry}
  218.     vmDescTable.SetElem(H, D);
  219.     Lock := vmDescTable.GetStatus = 0;
  220.   end;
  221.  
  222.   procedure VMM.GetMemV(var Pt; BlkSize : Word);
  223.     {-Allocate a memory block and return a Vmm "pointer" in P}
  224.   var
  225.     H : Word;
  226.     D : VmmDescriptor;
  227.     P : Pointer absolute Pt;
  228.   begin
  229.    if  (BlkSize <= MaxHeapAlloc)
  230.    and (BlkSize > 0)
  231.    and ((RamMaxAvail >= BlkSize)
  232.          or
  233.          (((EmsPagesAvail*EmsPage-VmmRamAreaSizeGlb >= BlkSize)
  234.             or
  235.            (DskMaxAvail-VmmRamAreaSizeGlb >= BlkSize))
  236.           and
  237.           (PageOut(BlkSize)))) then begin
  238.    {Scan RamFreeList for a free block or allocate a new one...}
  239.    { or page out until enough room is available}
  240.    { Don't allocate if there isn't enough room in Ems or on disk}
  241.    { to securely page out entire RamArea of all VMMs - prevent dead lock}
  242.      P := vmRamFreeList.GetFreeEntry(BlkSize); {Result cannot be nil}
  243.      {Convert to a VMM pointer and create new entry in descriptor table}
  244.      H := GetHandle;
  245.      if H = OutOfHandles then begin         {Descriptor table out of entries}
  246.        P := nil;
  247.        Exit;
  248.      end;
  249.      D.Location := vmInRam;                 {All other values are null}
  250.      D.RamPtr := P;                         {Point to block in Ram area}
  251.      D.Size := BlkSize;
  252.      vmDescTable.SetElem(H, D);             {Update descriptor table}
  253.      VmmPtrRec(P).Seg := H;                 {Handle goes in segment part of P}
  254.      VmmPtrRec(P).Ofs := VmmMark;           {Offset of VMMptr is always $FFFF}
  255.      vmLruQueue.Remove(H);
  256.      vmLruQueue.PushTail(H);                {Add the handle to the LRU queue}
  257.    end
  258.    else begin
  259.    {No space to allocate in Ram and PageOut failed}
  260.    { not enough memory or too many locked blocks}
  261.        P := nil;
  262.        Exit;
  263.    end;
  264.   end;
  265.  
  266.   procedure VMM.FreeMemV(var Pt);
  267.     {-Free a block and set P to nil}
  268.   var
  269.     H : Word;
  270.     P : Pointer absolute Pt;
  271.     D : VmmDescriptor;
  272.   begin
  273.     if VmmPtrRec(P).Ofs = VmmMark then begin
  274.       vmDescTable.GetElem(VmmPtrRec(P).Seg, D);
  275.       H := VmmPtrRec(P).Seg;
  276.       if vmDescTable.GetStatus = 0 then begin
  277.         case D.Location and vmLocation of
  278.           vmInRam : if vmRamFreeList.AddFreeEntry(D.Ptr, D.Size) = 0 then
  279.                       Error(epNonFatal+ecOutOfRamEntries);
  280.           vmInEms : if vmEmsFreeList.AddFreeEntry(D.Ptr, D.Size) = 0 then
  281.                       Error(epNonFatal+ecOutOfEmsEntries);
  282.           vmOnDsk : if vmDskFreeList.AddFreeEntry(D.Ptr, D.Size) = 0 then
  283.                       Error(epNonFatal+ecOutOfDskEntries);
  284.           else ErrorExit(204); {Invalid pointer operation}
  285.         end;
  286.         P := nil;
  287.         {Indicate that this handle is free}
  288.         FillChar(D, SizeOf(D), 0);
  289.         vmDescTable.SetElem(H, D);
  290.         {Remove it from the LRU queue}
  291.         vmLruQueue.Remove(H);
  292.       end
  293.       else
  294.         ErrorExit(213);
  295.     end
  296.     else
  297.       ErrorExit(204); {Invalid pointer operation}
  298.   end;
  299.  
  300.   function VMM.GetSize(var Pt) : Word;
  301.     {-Return size of block pointed to by Pt}
  302.   var
  303.     P : Pointer absolute Pt;
  304.     D : VmmDescriptor;
  305.   begin
  306.     vmDescTable.GetElem(VmmPtrRec(P).Seg, D);
  307.     if vmDescTable.GetStatus = 0 then
  308.       GetSize := D.Size
  309.     else
  310.       GetSize := 0;
  311.   end;
  312.  
  313.   function VMM.ClearRamArea : Boolean;
  314.     {-Page out all blocks unless they are locked}
  315.   begin
  316.     if RamMaxAvail < vmRamAreaSize then
  317.       ClearRamArea := PageOut(vmRamAreaSize)
  318.       {May fail if blocks are locked}
  319.     else
  320.       ClearRamArea := true;
  321.   end;
  322.  
  323.   function VMM.RamMaxAvail : LongInt;
  324.     {-Return size of the largest block available in RAM area}
  325.   begin
  326.     RamMaxAvail := vmRamFreeList.MaxFree;
  327.   end;
  328.  
  329.   function VMM.EmsMaxAvail : LongInt;
  330.     {-Return amount of memory available in Ems}
  331.   var
  332.     PagesFree   : LongInt;
  333.   begin
  334.     if not vmOptionsAreOn(vmUseEms) or (vmEmsToKeep = NoEms) then begin
  335.       EmsMaxAvail := 0;
  336.       Exit;
  337.     end;
  338.     PagesFree := EmsPagesAvail;
  339.     if (PagesFree <> EmsErrorCode) and (PagesFree >= vmEmsToKeep+4) then
  340.       EmsMaxAvail := MaxEmsBlock
  341.     else
  342.       EmsMaxAvail := vmEmsFreeList.MaxFree;
  343.   end;
  344.  
  345.   function VMM.DskMaxAvail : LongInt;
  346.     {-Return amount of space available on disk for VMM}
  347.   var
  348.     S : LongInt;
  349.     R : Registers;
  350.   begin
  351.     if not vmOptionsAreOn(vmUseDsk) or (vmSwapFName = '') then begin
  352.       DskMaxAvail := 0;
  353.       Exit;
  354.     end;
  355.     with R do begin
  356.       AX := $3600;
  357.       DX := Ord(Upcase(vmSwapFName[1]))-64;
  358.       MsDos(R);
  359.       if (BX = 0) or (AX = $FFFF) then
  360.         DskMaxAvail := 0
  361.       else begin
  362.         S := LongInt(AX)*LongInt(BX)*LongInt(CX)-vmDskToKeep;
  363.         DskMaxAvail := MaxLong(S, vmDskFreeList.MaxFree);
  364.       end;
  365.     end;
  366.   end;
  367.  
  368.   procedure VMM.vmOptionsOn(OptionFlags : Word);
  369.     {-Activate multiple options}
  370.   begin
  371.     SetFlag(vmOptions, OptionFlags and not BadVmmOptions);
  372.   end;
  373.  
  374.   procedure VMM.vmOptionsOff(OptionFlags : Word);
  375.     {-Deactivate multiple options}
  376.   var
  377.     SaveOptions : Word;
  378.   begin
  379.     SaveOptions := vmOptions and (vmUseDsk+vmUseEms);
  380.     ClearFlag(vmOptions, OptionFlags and not BadVmmOptions);
  381.     {Cannot clear both vmUseEms and vmUseDsk flags}
  382.     if vmOptions and (vmUseDsk+vmUseEms) = 0 then
  383.       vmOptions := vmOptions or SaveOptions;
  384.   end;
  385.  
  386.   function VMM.vmOptionsAreOn(OptionFlags : Word) : Boolean;
  387.     {-Return true if all specified options are on}
  388.   begin
  389.     vmOptionsAreOn := (vmOptions and OptionFlags = OptionFlags);
  390.   end;
  391.